package net.mikoo.seals.biz.manager;

import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import net.mikoo.seals.biz.mapper.ApplyMapper;
import net.mikoo.seals.biz.mapper.ApplyVerifyMapper;
import net.mikoo.seals.biz.mapper.DevicesActMapper;
import net.mikoo.seals.biz.mapper.DevicesMapper;
import net.mikoo.seals.biz.mapper.SealMapper;
import net.mikoo.seals.biz.mapper.WorkflowMapper;
import net.mikoo.seals.biz.mapper.WorkflowSettingMapper;
import net.mikoo.seals.common.enums.ApplyStatusEnum;
import net.mikoo.seals.common.enums.ApplyTypeEnum;
import net.mikoo.seals.common.enums.DevicesStatusEnum;
import net.mikoo.seals.common.enums.SealStatusEnum;
import net.mikoo.seals.common.enums.TakeStatusEnum;
import net.mikoo.seals.common.enums.VerifyStatusEnum;
import net.mikoo.seals.common.enums.WorkflowTypeEnum;
import net.mikoo.seals.common.exception.ParametersException;
import net.mikoo.seals.model.Apply;
import net.mikoo.seals.model.ApplyUpfile;
import net.mikoo.seals.model.ApplyVerify;
import net.mikoo.seals.model.Devices;
import net.mikoo.seals.model.DevicesAct;
import net.mikoo.seals.model.DevicesQuery;
import net.mikoo.seals.model.Seal;
import net.mikoo.seals.model.Workflow;
import net.mikoo.seals.model.WorkflowSetting;
import net.mikoo.seals.model.WorkflowSettingQuery;

@Service
public class ApplyManager {


	@Autowired
	private ApplyMapper applyMapper;

	@Autowired
	private ApplyVerifyMapper applyVerifyMapper;

	@Autowired
	private DevicesActMapper devicesActMapper;
	
	@Autowired
	private WorkflowSettingMapper workflowSettingMapper;

	@Autowired
	private DevicesMapper devicesMapper;

	@Autowired
	private WorkflowMapper workflowMapper;
	
	
	@Autowired
	private NoticeManager noticeManager;
	
	
	@Autowired
	private SealMapper sealMapper;
	
	public void checkParams(Apply apply) {
		
		if (apply == null) {
			throw new ParametersException("非法参数");
		}
		
		if (apply.getCompanyId() == null) {
			throw new ParametersException("非法参数");
		}
		
		if(apply.getSealId() == null && apply.getDevicesId() == null) {
			throw new ParametersException("非法参数");
		}
		
		if (StringUtils.isBlank(apply.getApplyType())) {
			throw new ParametersException("请选择申请类型");
		}
		
		if(apply.getApplyType().equals(ApplyTypeEnum.USED_APPLY.code())) {
			if(apply.getUpfileIds() == null || apply.getUpfileIds().size() == 0) {
				throw new ParametersException("请上传相关证明");
			}
			
			if (apply.getApplyTimes() == null || apply.getApplyTimes() <= 0) {
				throw new ParametersException("申请次数必须大于1次");
			}
		}else if(apply.getApplyType().equals(ApplyTypeEnum.TAKE_APPLY.code())) {
//			if(apply.getUpfileIds() == null || apply.getUpfileIds().size() == 0) {
//				throw new ParametersException("请上传相关证明");
//			}
			
			if(apply.getTakeStartTime() == null || apply.getTakeEndTime() == null) {
				throw new ParametersException("外带时间不能为空");
			}
		}else if(apply.getApplyType().equals(ApplyTypeEnum.TEST_APPLY.code())) {
			
			if(apply.getDevicesId() == null) {
				throw new ParametersException("DevicesId is null");
			}
		}
		
		if ( StringUtils.isBlank(apply.getCause())) {
			throw new ParametersException("请填写申请事由");
		}
		
		if(StringUtils.isBlank(apply.getUseSpecial())) {
			apply.setUseSpecial("N");
		}
		
	}
	
	public void exeApplyProcessor(Apply apply) {
		
		switch (apply.getApplyType()) {
		//测试申请
		case "TEST_APPLY":
			testApply(apply);
			break;
		//紧急申请
		case "URGENT_APPLY":
			urgentApply(apply);
			break;
		case "USED_APPLY":
			usedApply(apply);
			break;
		case "TAKE_APPLY":
			takeApply(apply);
			break;
		default:
			throw new ParametersException("请选择申请类型");
		}
	}
	
	
	/**
	 * 测试申请
	 * 无需审核 自动申请通过
	 * @param apply
	 */
	private void testApply(Apply apply) {
		
		if(apply.getDevicesId() == null) {
			throw new ParametersException("参数错误");
		}
		Devices devices = devicesMapper.selectInfoById(apply.getDevicesId());
		DevicesStatusEnum status = DevicesStatusEnum.getByCode(devices.getDevicesStatus());
		//如果不处于已安装状态不能申请测试使用
		if(status != DevicesStatusEnum.WAIT_TEST && status != DevicesStatusEnum.WAIT_UPLOAD_VOUCHER && status != DevicesStatusEnum.WAIT_ACTIVATE) {
			throw new ParametersException("申请请失败，当前状态不匹配");
		}
		
		Seal seal = sealMapper.selectInfoById(devices.getSealId());
		if(seal == null) {
			throw new ParametersException("申请的印章不存在");
		}
		
		
		//添加申请记录
		apply.setApplyTime(new Date());
		apply.setCreateTime(new Date());
		apply.setApplyStatus(ApplyStatusEnum.PASSED.code());
		apply.setVerifyResult("申请测试,系统自动审核通过");
		apply.setVerifyStartTime(new Date());
		apply.setVerifyEndTime(new Date());
		apply.setSealId(seal.getSealId());
		applyMapper.insert(apply);
		
		DevicesAct devicesAct = new DevicesAct();
		devicesAct.setSealId(apply.getSealId());
		devicesAct.setApplyType(apply.getApplyType());
		devicesAct.setApplyId(apply.getApplyId());
		devicesAct.setCompanyId(apply.getCompanyId());
		devicesAct.setDevicesId(apply.getDevicesId());
		devicesAct.setPartyId(apply.getPartyId());
		devicesAct.setTotalTimes(apply.getApplyTimes());
		devicesAct.setUseTimes(0);
		devicesAct.setCause(apply.getCause());
		devicesAct.setSealId(apply.getSealId());
		devicesAct.setApplyTime(apply.getApplyTime());
		devicesActMapper.insert(devicesAct);
		
		devices.setApplyTimes(devices.getApplyTimes() + apply.getApplyTimes());
//		devices.setDevicesStatus(DevicesStatusEnum.WAIT_UPLOAD_VOUCHER.code());
		devicesMapper.update(devices);
	}
	
	private void usedApply(Apply apply) {
		Seal seal = sealMapper.selectInfoById(apply.getSealId());
		if(seal == null) {
			throw new ParametersException("印章不存在");
		}
		
		if(!seal.getCompanyId().equals(apply.getCompanyId()) ) {
			throw new ParametersException("无权申请");
		}
		
		if(!seal.getSealStatus().equals(SealStatusEnum.ENABLE.code())) {
			throw new ParametersException("印章未启用");
		}
		
		
		DevicesQuery devicesQuery = new DevicesQuery();
		devicesQuery.setSealId(seal.getSealId());
		Devices devices = devicesMapper.selectInfoByQuery(devicesQuery);
		
		if(devices == null) {
			throw new IllegalStateException("设备不存在");
		}
		
		apply.setApplyTime(new Date());
		apply.setCreateTime(new Date());
		apply.setApplyStatus(ApplyStatusEnum.PENDING.code());
		apply.setVerifyStartTime(new Date());
		apply.setDevicesId(devices.getDevicesId());
		applyMapper.insert(apply);
		
		//添加附件
		addUpfile(apply);
		
		//执行审批流程
		exeVerifyProcess(apply,seal);

		seal.setApplyTimes(seal.getApplyTimes() + 1);
		sealMapper.update(seal);
	}
	
	
	private void exeVerifyProcess(Apply apply,Seal seal) {
		
		//如果使用特批流程
		Long workflowId = null;
		if(apply.getUseSpecial().equals("Y")) {
			workflowId = seal.getSpecialWorkflowId();
		}else {
			workflowId = seal.getWorkflowId();
		}
		
		Workflow workflow = workflowMapper.selectInfoById(workflowId);
		
		String workflowType = workflow.getWorkflowType();
		WorkflowSettingQuery query = new WorkflowSettingQuery();
		query.setWorkflowId(workflowId);
		List<WorkflowSetting> settings =  workflowSettingMapper.selectListByQuery(query);
		
		if(settings == null || settings.isEmpty()) {
			throw new ParametersException("流程信息有误，请联系管理员");
		}
		
		if(workflowType.equals(WorkflowTypeEnum.QUEUE.code())) {
			for (int i = 0; i < settings.size(); i++) {
				WorkflowSetting setting= settings.get(i);
				
				ApplyVerify verify  = new ApplyVerify();
				
				if(i == 0) {
					verify.setVerifyStatus(VerifyStatusEnum.PENDING.code());
				}else {
					verify.setVerifyStatus(VerifyStatusEnum.WAIT.code());
				}
				verify.setCompanyId(apply.getCompanyId());
				verify.setPartyId(setting.getPartyId());
				verify.setApplyId(apply.getApplyId());
				verify.setSequence(setting.getSequence());
				applyVerifyMapper.insert(verify);
				
				//如果是待办则发送通知
				if(verify.getVerifyStatus().equals(VerifyStatusEnum.PENDING.code())) {
					noticeManager.apply(apply, seal, verify);
				}
			}
			
		}else{
			for (int i = 0; i < settings.size(); i++) {
				WorkflowSetting setting= settings.get(i);
				
				ApplyVerify verify  = new ApplyVerify();
				verify.setVerifyStatus(VerifyStatusEnum.PENDING.code());
				verify.setCompanyId(apply.getCompanyId());
				verify.setPartyId(setting.getPartyId());
				verify.setApplyId(apply.getApplyId());
				verify.setSequence(setting.getSequence());
				applyVerifyMapper.insert(verify);
				
				//如果是待办则发送通知
				if(verify.getVerifyStatus().equals(VerifyStatusEnum.PENDING.code())) {
					noticeManager.apply(apply, seal, verify);
				}
				
			}
			
		}
		
	}

	/**
	 * 紧急申请
	 * @param apply
	 */
	private void urgentApply(Apply apply) {
		Devices devices = devicesMapper.selectInfoById(apply.getDevicesId());
		
		//判断是否禁用
		if(!devices.getIsActivate().equals("Y")) {
			throw new ParametersException("设备已被禁用，请联系运营商");
		}
		
		//判断是否过期
		if(devices.getExpireDate().before(new Date())){
			throw new ParametersException("设备已过期，请联系运营商续签");
		}
		
		if(devices.getWorkflowId() == null) {
		    throw new ParametersException("未设置审核流程，不能申请使用");
		}
		
		//判断是否已处于正常状态(注：紧急申请可能设备已在借出人手中)
		if(!devices.getDevicesStatus().equals(DevicesStatusEnum.ACTIVATE.code())) {
			throw new ParametersException("申请失败，当前状态不匹配");
		}
		
		//判断紧急申请次数
		Integer limitUrgentApply = devices.getLimitUrgentApply();
		if(limitUrgentApply == 0) {
			throw new ParametersException("此设备不能紧急申请");
		}
		
		//1.申请记录
		apply.setApplyTime(new Date());
		apply.setCreateTime(new Date());
		apply.setApplyStatus(ApplyStatusEnum.PASSED.code());
		apply.setVerifyResult("紧急,系统自动审核通过");
		apply.setVerifyStartTime(new Date());
		apply.setVerifyEndTime(new Date());
		applyMapper.insert(apply);
		
		addUpfile(apply);
		//2.查询审核人
		
		Long workflowId = devices.getWorkflowId();
		//紧急申请无需判断审核类型
		//String workflowType = devices.getWorkflowType();
		
		WorkflowSettingQuery query = new WorkflowSettingQuery();
		query.setWorkflowId(workflowId);
		List<WorkflowSetting> settings =  workflowSettingMapper.selectListByQuery(query);
		for (WorkflowSetting setting : settings) {
			//3.添加待审核记录
			ApplyVerify verify = new ApplyVerify();
			verify.setApplyId(apply.getApplyId());
			verify.setPartyId(setting.getPartyId());
			verify.setVerifyTime(new Date());
			verify.setVerifyResult("紧急申请系统自动审核通过");
			verify.setVerifyStatus(VerifyStatusEnum.PASSED.code());
			applyVerifyMapper.insert(verify);
		}
		
		DevicesAct devicesAct = new DevicesAct();
		devicesAct.setApplyId(apply.getApplyId());
		devicesAct.setCompanyId(apply.getCompanyId());
		devicesAct.setDevicesId(apply.getDevicesId());
		devicesAct.setPartyId(apply.getPartyId());
		devicesAct.setTotalTimes(1);//紧急申请最多只能申请一次
		devicesAct.setUseTimes(0);
		devicesAct.setCause(apply.getCause());
		
		devicesActMapper.insert(devicesAct);

		devices.setApplyTimes(devices.getApplyTimes() + apply.getApplyTimes());
		devicesMapper.update(devices);
	}
	
	/**
	 * 外带申请
	 * @param apply
	 */
	private void takeApply(Apply apply) {
		
		//申请外带校验外带时间段
		if(apply.getTakeStartTime() == null || apply.getTakeStartTime() == null) {
			throw new ParametersException("请选择外带时间");
		}
		
		if(apply.getTakeStartTime().after(apply.getTakeStartTime())) {
			throw new ParametersException("外带开始时间不能大于外带结束时间");
		}
		
		if(StringUtils.isBlank(apply.getTakeDestination())) {
			throw new ParametersException("请设置外带地址");
		}
		
		//Devices devices = devicesMapper.selectInfoById(apply.getDevicesId());
		
		
		
		DevicesQuery devicesQuery = new DevicesQuery();
		devicesQuery.setSealId(apply.getSealId());
		Devices devices = devicesMapper.selectInfoByQuery(devicesQuery);
		
		if(devices == null) {
			throw new ParametersException("设备不存在");
		}
		
		
		if(!devices.getDevicesStatus().equals(DevicesStatusEnum.ACTIVATE.code())) {
			throw new ParametersException("无效设备不允许申请");
		}
		
		if(devices.getTakeStatus().equals(TakeStatusEnum.WAIT_RETURN.code())) {
			throw new ParametersException("设备已借出，不能再申请外带");
		}
		
		
		usedApply(apply);
		
	}
	
	
	private void addUpfile(Apply apply) {
		List<Long>  upfileIds = apply.getUpfileIds();
		if(upfileIds != null && !upfileIds.isEmpty()) {
			
			for (Long upfileId : upfileIds) {
				ApplyUpfile upfile = new ApplyUpfile();
				upfile.setUpfileId(upfileId);
				upfile.setApplyId(apply.getApplyId());
				applyMapper.insertUpfile(upfile);
			}
		}
	}

}
